home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Atari Mega Archive 1
/
Atari Mega Archive - Volume 1.iso
/
telecomm
/
sticpsrc.lzh
/
SOURCE.ARC
/
AX25.C
< prev
next >
Wrap
C/C++ Source or Header
|
1990-10-06
|
14KB
|
480 lines
/* Low level AX.25 frame processing - address header */
#include <stdio.h>
#include "global.h"
#include "mbuf.h"
#include "iface.h"
#include "timer.h"
#include "arp.h"
#include "slip.h"
#include "ax25.h"
#include "lapb.h"
#include <ctype.h>
char axbdcst[AXALEN]; /* Broadcast address (QST-0), network format */
int digipeat = 1; /* Controls single-band standard digipeating */
struct mbuf *axloopq = NULLBUF; /* Loopback queue for AX.25 packets */
/* Send IP datagrams across an AX.25 link */
int
ax_send(bp,interface,gateway,precedence,delay,throughput,reliability)
struct mbuf *bp;
struct interface *interface;
int32 gateway;
char precedence;
char delay;
char throughput;
char reliability;
{
char *hw_addr,*res_arp();
struct ax25_cb *axp,*find_ax25(),*open_ax25();
struct ax25 addr;
struct ax25_addr destaddr;
struct mbuf *tbp;
extern int16 axwindow;
void ax_incom();
int16 size,bsize,seq;
if((hw_addr = res_arp(interface,ARP_AX25,gateway,bp)) == NULLCHAR)
return 0; /* Wait for address resolution */
if(delay || (!reliability && !(interface->flags & IF_CONNECT_MODE))){
/* Use UI frame */
return (*interface->output)(interface,hw_addr,
interface->hwaddr,PID_FIRST|PID_LAST|PID_IP,bp);
}
/* Reliability is needed; use I-frames in AX.25 connection */
memcpy(destaddr.call,hw_addr,ALEN);
destaddr.ssid = hw_addr[ALEN];
if((axp = find_ax25(&destaddr,(struct ax25_addr *)interface->hwaddr)) == NULLAX25 ||
(axp->state != CONNECTED && axp->state != SETUP)){
/* Open a new connection or reinitialize the old one */
atohax25(&addr,hw_addr,(struct ax25_addr *)interface->hwaddr);
axp = open_ax25(&addr,axwindow,ax_incom,NULLVFP,NULLVFP,interface,(char *)0);
if(axp == NULLAX25){
free_p(bp);
return -1;
}
}
/* If datagram is too big for one frame, send all but the last with
* the extension PID. Note: the copy to a new buf is necessary because
* AX.25 may continue retransmitting the frame after a local TCB has
* gone away, and using the buf directly would cause heap garbage to be
* transmitted. Besides, nobody would ever use AX.25 anywhere
* high performance is needed anyway...
*/
bsize = len_mbuf(bp);
seq = 0;
while(bsize != 0){
size = min(bsize,axp->paclen);
/* Allocate buffer, allowing space for PID */
if((tbp = alloc_mbuf(size + 1)) == NULLBUF)
break; /* out of memory! */
*tbp->data = PID_IP;
if(seq++ == 0)
*tbp->data |= PID_FIRST; /* First in sequence */
if(size == bsize)
*tbp->data |= PID_LAST; /* That's all of it */
/* else more to follow */
tbp->cnt = 1;
tbp->cnt += pullup(&bp,tbp->data + 1,size);
send_ax25(axp,tbp);
bsize -= size;
}
free_p(bp); /* Shouldn't be necessary */
return 0;
}
/* Add AX.25 link header and send packet.
* Note that the calling order here must match ec_output
* since ARP also uses it.
*/
ax_output(interface,dest,source,pid,data)
struct interface *interface;
char *dest; /* Destination AX.25 address (7 bytes, shifted) */
/* Also includes digipeater string */
char *source; /* Source AX.25 address (7 bytes, shifted) */
char pid; /* Protocol ID */
struct mbuf *data; /* Data field (follows PID) */
{
struct mbuf *abp,*cbp,*htonax25();
struct ax25 addr;
/* Allocate mbuf for control and PID fields, and fill in */
if((cbp = pushdown(data,2)) == NULLBUF){
free_p(data);
return -1;
}
cbp->data[0] = UI;
cbp->data[1] = pid;
atohax25(&addr,dest,(struct ax25_addr *)source);
if((abp = htonax25(&addr,cbp)) == NULLBUF){
free_p(cbp); /* Also frees data */
return -1;
}
/* This shouldn't be necessary because redirection has already been
* done at the IP router layer, but just to be safe...
*/
if(interface->forw != NULLIF)
return (*interface->forw->raw)(interface->forw,abp);
else
return (*interface->raw)(interface,abp);
}
/* Process incoming AX.25 packets.
* After optional tracing, the address field is examined. If it is
* directed to us as a digipeater, repeat it. If it is addressed to
* us or to QST-0 or NODES-0, kick it upstairs depending on the protocol ID.
*/
int
ax_recv(interface,bp)
struct interface *interface;
struct mbuf *bp;
{
void arp_input();
int ip_route();
struct ax25_addr addr,*ap;
struct mbuf *htonax25(),*hbp;
struct ax25 hdr;
register struct ax25_cb *axp;
struct ax25_cb *find_ax25(),*cr_ax25();
register struct ax25_call *axc;
struct ax25_call *axd;
int timerscale,setdigi;
extern int16 t1init,t2init,t3init,t4init;
/* Pull header off packet and convert to host structure */
if(ntohax25(&hdr,&bp) < 0){
/* Something wrong with the header */
free_p(bp);
return;
}
/* Update the users liatifor persistence calculation */
upd_nusers(interface,hdr.source.call);
/* Update the MHEARD liatifor this interface */
if(interface->mheard != 0){ /* first check if we have to keep it */
updmheard(interface,1,&hdr); /* update the liat */
}
/* check source address. it must NOT appear in the exclude liat */
ASSIGN(addr,hdr.source); /* get the source address */
addr.ssid = 0; /* discard the SSID */
if((axc = find_axcall(ax25_excl,&addr)) != NULLAXCALL &&
((axc->flags & MULTI_IF) || axc->interface == interface)) {
free_p(bp);
return;
}
timerscale = hdr.ndigis + 1; /* default scaling of timer values */
/* Scan, looking for our call in the repeater fields, if any.
* Repeat appropriate packets.
*/
for(ap = &hdr.digis[0]; ap < &hdr.digis[hdr.ndigis]; ap++){
if(ap->ssid & REPEATED)
continue; /* Already repeated */
/* Check if packet is directed to us as a digipeater */
if((axc = find_axcall(ax25_digi,ap)) != NULLAXCALL){
/* check dest address. it must NOT appear in the exclude liat */
ASSIGN(addr,hdr.dest); /* get the dest address */
addr.ssid = 0; /* discard the SSID */
if((axd = find_axcall(ax25_excl,&addr)) != NULLAXCALL &&
((axd->flags & MULTI_IF) ||
axd->interface == interface || axd->interface == axc->interface)) {
free_p(bp);
return; /* if any doubt, refuse it */
}
switch (axc->mode) /* check the digi mode */
{
case DIGIPEAT: /* bare digipeater */
if (axc->interface == interface){ /* this band? */
if (!digipeat) /* in-band digi disabled? */
break; /* throw it away */
} else { /* not "home", gateway request */
if (axc->flags & DIGIGATEWAY &&
(axd = find_axcall(ax25_digi,interface->hwaddr))
!= NULLAXCALL &&
axd->mode == DIGIPEAT &&
axd->flags & DIGIGATEWAY){
/* swap callsign and interface */
ASSIGN(*ap,*((struct ax25_addr *) interface->hwaddr));
interface = axc->interface;
} else {
break; /* gateway conditions not fulfilled... */
}
}
/* kick it back out */
ap->ssid |= REPEATED;
if((hbp = htonax25(&hdr,bp)) != NULLBUF){
if(interface->forw != NULLIF)
(*interface->forw->raw)(interface->forw,hbp);
else
(*interface->raw)(interface,hbp);
tnc2_kissrcv(interface,&hdr,bp,4);
bp = NULLBUF;
}
break;
case DIGICONNECT: /* digipeater simulating connection */
if ((axc->flags & MULTI_IF) ||
axc->interface == interface ||
(axc->flags & DIGIGATEWAY)){
/* address is okay */
if (bp != NULLBUF){
timerscale = (int) (ap - &hdr.digis[0]) + 1;
goto for_us;/* handle as if addressed to us */
}
}
break;
}
}
tnc2_kissrcv(interface,&hdr,bp,4);
free_p(bp); /* Dispose if not forwarded */
return;
}
/* Packet has passed all repeaters, now look at destination */
if((axc = find_axcall(ax25_call,&hdr.dest)) == NULLAXCALL ||
!((axc->flags & MULTI_IF) || axc->interface == interface)) {
/* Not for us, or wrong interface for this callsign */
tnc2_kissrcv(interface,&hdr,bp,3);
free_p(bp);
return;
}
if(bp == NULLBUF){
/* Nothing left */
return;
}
/* Sneak a peek at the control field. This kludge is necessary because
* AX.25 lacks a proper protocol ID field between the address and LAPB